home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Think Class Libraries / CAccordionPane 1.0 / CAccordionPane.c next >
Encoding:
C/C++ Source or Header  |  1994-11-30  |  14.1 KB  |  499 lines  |  [TEXT/KAHL]

  1. /******************************************************************************
  2.  CAccordionPane.c
  3.  
  4.     This set of classes implement another method for altering the size and 
  5.     location of sub panes when the primary pane is resized.
  6.  
  7.     TCL sub panes are related to the edges of the primary pane. While this 
  8.     is quite flexible it does make difficult the need to relate panes as a 
  9.     sequence and as a proportion of the whole.
  10.  
  11.     The CAccordionPane classes relates panes as a sequence of vertical or 
  12.     horizontal sub-panes. Each pane is either elastic or fixed. When an 
  13.     accordion pane is resized each sub-pane is resized so as to keep the order 
  14.     and sub-pane proportionality intact. For example, three horizontally 
  15.     arranged panes each having 1/3 of the available width can be encoded with 
  16.     a CHAccordionPane.
  17.  
  18.     More complex plane arrangements can be had by placing accordion panes 
  19.     within accordion panes. Thus, for example, a SmallTalk like browser is no 
  20.     more than a CVAccordionPane with two sub-panes. The first sub-pane is a 
  21.     CHAccordionPane composed of three CArrayPanes. The second sub-pane is a 
  22.     CEditText pane.
  23.  
  24.     To use the accordion panes simply a matter of making it the enclosure of
  25.     the sub-panes. Each time a pane is added as a subpane of another
  26.     AddSubview() is called. AddSubview() is overridden by CVAccordionPane
  27.     and CHAccordionPane to update the proportion tables. If the sub-pane
  28.     is to have a proportion other than make a call to SetSubviewPortion().
  29.     
  30.     NOTE: After all the panes have been added I recommend that you call
  31.     ForceResize() on the top-most accordion pane. This will ensure that the
  32.     sub-panes are sized and located correctlty before they are first drawn.
  33.  
  34.     NOTE: ForceResize() is very slow....
  35.  
  36.     NOTE: The sub-panes are resized as though a call to FitToEnclosure() 
  37.     was made. This means than the sub-panes do not share any edges. For my
  38.     current interface needs this is acceptable. However, at some point I plan
  39.     to modify ForceResize() to selectively resize sub-panes either as FitTo-
  40.     Enclosure() or FitToEnclFrame(). The default will remain FitToEnclosure().
  41.     
  42.     Copyright (C) 1993 by Brown University. All rights reserved.
  43.  
  44.     Permission is granted to any individual or institution to use, copy,
  45.     or redistribute the binary version of this software and its
  46.     documentation provided this notice and the copyright notices are
  47.     retained.  Permission is granted to any individual or non-profit
  48.     institution to use, copy, modify, or redistribute the source files
  49.     of this software provided this notice and the copyright notices are
  50.     retained.  This software may not be distributed for profit, either
  51.     in original form or in derivative works, nor can the source be
  52.     distributed to other than an individual or a non-profit institution.
  53.     Any  individual or group interested in seeing and/or using these
  54.     source files but who are prevented from doing so by the above
  55.     constraints should contact Don Wolfe, Vice-President for Computer 
  56.     Systems at Brown University, (401) 863-7247, for possible
  57.     software licensing of the source developed at Brown.
  58.  
  59.     Brown University and Andrew James Gilmartin make no representations
  60.     about the suitability of this software for any purpose.
  61.  
  62.      BROWN UNIVERSITY AND ANDREW JAMES GILMARTIN GIVE NO WARRANTY, EITHER
  63.     EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION PROVIDED,
  64.     INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY AND
  65.     WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
  66.  
  67.     AUTHOR: Andrew_Gilmartin@Brown.Edu
  68.     MODIFIED: 93-03-05
  69.  
  70. ******************************************************************************/
  71.  
  72. #include "CAccordionPane.h"
  73.  
  74.  
  75. #define ACCORDION_DEBUG // DebugStr( (StringPtr) "\p" );
  76.  
  77.  
  78.  
  79. /******************************************************************************
  80.  IAccordionPane (also defined as IHAccordionPane & IVAccordionPane)
  81.  
  82.     Initialize the accordion pane and its instance variables. NOTE: 
  83.     CAccordionPane should not be instanciated directly and thus the need
  84.     for the ASSERT().
  85. ******************************************************************************/
  86.  
  87. void CAccordionPane::IAccordionPane
  88.     ( CView *anEnclosure
  89.     , CBureaucrat *aSupervisor
  90.     , short aWidth
  91.     , short aHeight
  92.     , short aHEncl
  93.     , short aVEncl
  94.     , SizingOption aHSizing
  95.     , SizingOption aVSizing )
  96. {
  97.     ACCORDION_DEBUG
  98.  
  99.     ASSERT( member( this, CHAccordionPane ) || member( this, CVAccordionPane ) );
  100.  
  101.     IPane
  102.         ( anEnclosure
  103.         , aSupervisor
  104.         , aWidth
  105.         , aHeight
  106.         , aHEncl
  107.         , aVEncl
  108.         , aHSizing
  109.         , aVSizing );
  110.  
  111.     itsSubviewPortions = new CRunArray;
  112.     itsSubviewPortions->IRunArray();
  113.  
  114.     itsTotalFixedSize = 0;
  115.  
  116. } /* IAccordionPane */
  117.  
  118.  
  119.  
  120. /******************************************************************************
  121.  Dispose
  122.  
  123.     Dispose of the proportion information and then the instance itself.
  124. ******************************************************************************/
  125.  
  126. void CAccordionPane::Dispose( void )
  127. {
  128.     ACCORDION_DEBUG
  129.  
  130.     ForgetObject( itsSubviewPortions );    
  131.     inherited::Dispose();
  132.  
  133. } /* Dispose */
  134.  
  135.  
  136.  
  137. /******************************************************************************
  138.  ChangeSize
  139.  
  140.     Override the default change size method. This method calls the inherited
  141.     method to change its own size pretending that there are no subviews. Once 
  142.     its size has changed all the subviews are changed by ForceResize().
  143. ******************************************************************************/
  144.  
  145. void CAccordionPane::ChangeSize( Rect *delta, Boolean redraw )
  146. {
  147.     CList* theSubviews;
  148.  
  149.     ACCORDION_DEBUG
  150.  
  151.         /* Change my size but not my subviews' size */
  152.             
  153.     theSubviews = itsSubviews;
  154.     itsSubviews = NULL;
  155.     inherited::ChangeSize( delta, redraw );
  156.     itsSubviews = theSubviews;
  157.  
  158.         /* Change the subviews size */
  159.  
  160.     ForceResize( redraw );
  161.  
  162. } /* ChangeSize */
  163.  
  164.  
  165.  
  166. /******************************************************************************
  167.  ForceResize
  168.  
  169.     See CVAccordionPane::ForceResize().
  170. ******************************************************************************/
  171.  
  172. void CAccordionPane::ForceResize( Boolean redraw )
  173. {
  174.     ACCORDION_DEBUG
  175.  
  176.     SubclassResponsibility();
  177.  
  178. } /* ForceResize */
  179.  
  180.  
  181.  
  182. /******************************************************************************
  183.  SetSubviewPortion
  184.  
  185.     Elastic subviews can be given different proportions of the available
  186.     pane size (width or height). For example, you might want to give the "top" 
  187.     pane 1/3 of the space and the "bottom" pane 2/3 of the space. Thus, the 
  188.     top plane would have one portion of the space and the bottom pane two 
  189.     portions of the space. Call SetSubviewPortion() to assign the proportion. 
  190.     By default all panes have equal portions of the space. Note that the space 
  191.     given to an elastic pane is based on the sum of all portions minus the 
  192.     size of fixed panes. Also note that not all elastic planes with the same
  193.     proportion will have the same size (See ForceResize).
  194. ******************************************************************************/
  195.  
  196. void CAccordionPane::SetSubviewPortion
  197.     ( CPane* aSubview
  198.     , short aPortion
  199.     , Boolean redraw )
  200. {
  201.     long index;
  202.     
  203.     ACCORDION_DEBUG
  204.  
  205.     index = itsSubviews->FindIndex( aSubview );
  206.     
  207.     if ( index > 0 /* && should check that sub is elastic */ )
  208.     {
  209.         itsSubviewPortions->SetValue( index, aPortion );
  210.         
  211.         if ( redraw )
  212.             ForceResize( redraw );
  213.     }
  214.  
  215. } /* SetSubviewPortion */
  216.  
  217.  
  218.  
  219. /******************************************************************************
  220.  ForceResize
  221.  
  222.     The panes are distributed down the accordion pane in their subview order.
  223.     Each elastic plane is given its porportion of the height remaining after 
  224.     removing the height necessary to accomodate the fixed panes. Since the
  225.     height remaining may not be divisible by the number of portions the extra
  226.     height is proportionally distributed to the elastic panes; thus, not all
  227.     panes with the same proportion of space will have the same height.
  228. ******************************************************************************/
  229.  
  230. void CVAccordionPane::ForceResize( Boolean redraw )
  231. {
  232.     short theTotalSubviews; // the number of subviews
  233.     short theTotalPortions; // the sum of all elastic subview's proportions
  234.     short theTotalWidth;    // the width of this pane
  235.     short theTotalHeight;   // the height of this pane
  236.     short thePortionSize;   // the height of one portion
  237.     short thePortionExtra;  // extra height to distribute to portions
  238.     short index;            // index into the subview list
  239.     long y;                 // vertical location of subview
  240.     short theNewHeight;     // height of the subview
  241.     short thePortions;      // the subview's portion
  242.     CPane* thePane;         // the currrent subview
  243.     Rect delta;             // how the subview should change size
  244.  
  245.     ACCORDION_DEBUG
  246.  
  247.         /* Do we have any subviews to process */
  248.  
  249.     theTotalSubviews = itsSubviews == NULL ? 0 : itsSubviews->GetNumItems();
  250.     if ( theTotalSubviews == 0 )
  251.         return;
  252.     
  253.         /* How many subview portions do we have? */
  254.     
  255.     theTotalPortions = itsSubviewPortions->SumRange( 1, itsSubviewPortions->GetNumItems() );
  256.  
  257.         /* How many pixels. */
  258.  
  259.     theTotalHeight = this->height;
  260.     theTotalWidth = this->width;
  261.  
  262.         /* How many pixels is given to each portion */
  263.  
  264.     thePortionSize = ( theTotalHeight - itsTotalFixedSize ) / theTotalPortions;
  265.     
  266.         /*
  267.             Because of round off we might have to give each portion some extra pixels.
  268.             How many extra pixels remain
  269.          */
  270.         
  271.     thePortionExtra = ( theTotalHeight - itsTotalFixedSize ) - ( thePortionSize * theTotalPortions );
  272.  
  273.         /* Resize each subview */
  274.  
  275.         /* Constants */
  276.         
  277.     delta.top = 0;
  278.     delta.left = 0;
  279.     
  280.         /* Vertical location of next subview */
  281.         
  282.     y = 0;
  283.     
  284.     for ( index = 1; index <= theTotalSubviews; index++ )
  285.     {
  286.             /* Get subview (we know that they are CPanes) */
  287.             
  288.         thePane = (CPane*) itsSubviews->NthItem( index );
  289.         
  290.             /* What is the subview's new height? */
  291.         
  292.         if ( thePane->vSizing == sizELASTIC )
  293.         {
  294.                 /* Distribute its portion of the height */
  295.  
  296.             thePortions = itsSubviewPortions->GetValue( index );
  297.             theNewHeight = thePortionSize * thePortions;
  298.             
  299.                 /* Distribute some of the extra height */
  300.                 
  301.             if ( thePortionExtra > 0 )
  302.             {
  303.                 theNewHeight += Min( thePortions, thePortionExtra );
  304.                 thePortionExtra -= thePortions;
  305.             }
  306.         }
  307.         else
  308.         {
  309.             theNewHeight = thePane->height;
  310.         }
  311.  
  312.             /* Place the pane */
  313.             
  314.         thePane->Place( 0, y, FALSE );
  315.  
  316.             /* Change the pane's size */
  317.  
  318.         delta.bottom = theNewHeight - thePane->height;    
  319.         delta.right = thePane->hSizing == sizELASTIC ? theTotalWidth - thePane->width : 0;
  320.         thePane->ChangeSize( &delta, redraw );
  321.         
  322.             /* Location for next subview */
  323.  
  324.         y += theNewHeight;
  325.     }
  326.  
  327. } /* ForceResize */
  328.  
  329.  
  330.  
  331. /******************************************************************************
  332.  AddSubview
  333.  
  334.     Add the subview to itsSubviews and then update the proportion list. All
  335.     fixed subviews have a portion of zero. The default proportion for elastic
  336.     panes if one.
  337. ******************************************************************************/
  338.  
  339. void CVAccordionPane::AddSubview( CView* aSubview )
  340. {
  341.     CPane* thePane = (CPane*) aSubview;
  342.  
  343.     ACCORDION_DEBUG
  344.  
  345.         /* Subviews have to be CPanes or a subclass */
  346.         
  347.     ASSERT( member( aSubview, CPane ) );
  348.  
  349.     inherited::AddSubview( aSubview );
  350.     
  351.     if ( thePane->vSizing != sizELASTIC )
  352.     {
  353.         itsTotalFixedSize += thePane->height;
  354.         itsSubviewPortions->InsertValue( itsSubviews->GetNumItems(), 0, 1 );
  355.     }
  356.     else
  357.     {
  358.         itsSubviewPortions->InsertValue( itsSubviews->GetNumItems(), 1, 1 );
  359.     }
  360.     
  361. } /* AddSubview */
  362.  
  363.  
  364.  
  365. /******************************************************************************
  366.  ForceResize
  367.  
  368.     See comments for CVAccordionPane::ForceResize().
  369. ******************************************************************************/
  370.  
  371. void CHAccordionPane::ForceResize( Boolean redraw )
  372. {
  373.     short theTotalSubviews;
  374.     short theTotalPortions;
  375.     short theTotalWidth;
  376.     short theTotalHeight;
  377.     short thePortionSize;
  378.     short thePortionExtra;
  379.     short index;
  380.     long x;
  381.     short theNewWidth;
  382.     short thePortions;
  383.     CPane* thePane;
  384.     Rect delta;
  385.  
  386.     ACCORDION_DEBUG
  387.  
  388.         /* Do we have any subviews to process */
  389.  
  390.     theTotalSubviews = itsSubviews == NULL ? 0 : itsSubviews->GetNumItems();
  391.     if ( theTotalSubviews == 0 )
  392.         return;
  393.     
  394.         /* How many subview portions do we have? */
  395.     
  396.     theTotalPortions = itsSubviewPortions->SumRange( 1, itsSubviewPortions->GetNumItems() );
  397.  
  398.         /* How many pixels. */
  399.  
  400.     theTotalWidth = this->width;
  401.     theTotalHeight = this->height;
  402.  
  403.         /* How pany pixels if given to each portion */
  404.         
  405.     thePortionSize = ( theTotalWidth - itsTotalFixedSize ) / theTotalPortions;
  406.     
  407.         /*
  408.             Because of round off we might have to give each portion some extra pixels.
  409.             How many extra pixels remain
  410.          */
  411.         
  412.     thePortionExtra = ( theTotalWidth - itsTotalFixedSize ) - ( thePortionSize * theTotalPortions );
  413.  
  414.         /* Resize each subview */
  415.  
  416.         /* Constants */
  417.         
  418.     delta.top = 0;
  419.     delta.left = 0;
  420.     
  421.         /* Horizontal location of next subview */
  422.         
  423.     x = 0;
  424.     
  425.     for ( index = 1; index <= theTotalSubviews; index++ )
  426.     {
  427.             /* Get subview (we know that they are CPanes) */
  428.             
  429.         thePane = (CPane*) itsSubviews->NthItem( index );
  430.         
  431.             /* What is the subview's new height? */
  432.         
  433.         if ( thePane->hSizing == sizELASTIC )
  434.         {
  435.                 /* Distribute its portion of the height */
  436.  
  437.             thePortions = itsSubviewPortions->GetValue( index );
  438.             theNewWidth = thePortionSize * thePortions;
  439.             
  440.                 /* Distribute some of the extra height */
  441.                 
  442.             if ( thePortionExtra > 0 )
  443.             {
  444.                 theNewWidth += Min( thePortions, thePortionExtra );
  445.                 thePortionExtra -= thePortions;
  446.             }
  447.         }
  448.         else
  449.         {
  450.             theNewWidth = thePane->width;
  451.         }
  452.  
  453.             /* Place the pane */
  454.             
  455.         thePane->Place( x, 0, FALSE );
  456.  
  457.             /* Change the pane's size */
  458.  
  459.         delta.bottom = thePane->vSizing == sizELASTIC ? theTotalHeight - thePane->height: 0;
  460.         delta.right = theNewWidth - thePane->width;    
  461.         thePane->ChangeSize( &delta, redraw );
  462.         
  463.             /* Location for next subview */
  464.  
  465.         x += theNewWidth;
  466.     }
  467.  
  468. } /* ForceResize */
  469.  
  470.  
  471.  
  472. /******************************************************************************
  473.  AddSubview
  474.  
  475.     See comments for CVAccordionPane::AddSubview().
  476. ******************************************************************************/
  477.  
  478. void CHAccordionPane::AddSubview( CView* aSubview )
  479. {
  480.     CPane* thePane = (CPane*) aSubview;
  481.  
  482.     ACCORDION_DEBUG
  483.  
  484.     ASSERT( member( aSubview, CPane ) );
  485.  
  486.     inherited::AddSubview( aSubview );
  487.     
  488.     if ( thePane->hSizing != sizELASTIC )
  489.     {
  490.         itsTotalFixedSize += thePane->width;
  491.         itsSubviewPortions->InsertValue( itsSubviews->GetNumItems(), 0, 1 );
  492.     }
  493.     else
  494.     {
  495.         itsSubviewPortions->InsertValue( itsSubviews->GetNumItems(), 1, 1 );
  496.     }
  497.     
  498. } /* AddSubview */
  499.